#pragma once

#include "Common.hpp"
#include "InetAddr.hpp"
#include "Socket.hpp"
#include <functional>
#include <sys/wait.h>

//定义IO服务接口
typedef std::function<void(std::shared_ptr<Socket_t>&, InetAddr&)> ioservice_t; 

class TcpServer
{
public:
    TcpServer(uint16_t port) : _port(port) 
    {
        //创建套接字并置为监听状态
        _listensock->BuildListenSocket(_port);
    }

    //启动服务
    void Start(ioservice_t service)
    {
        _isrunning = true;
        while(_isrunning)
        {
            //接受客户端的连接
            InetAddr client;
            auto sock = _listensock->Accept(&client);
            if(sock == nullptr)
            {
                continue; // 接受失败，重新接受
            }

            //创建子进程，由子进程与客户端交互，当前进程继续接受链接
            pid_t id = fork();
            if(id < 0)
            {
                //创建子进程失败，直接退出
                std::cerr << "fork error" << std::endl;
                exit((int)exit_code::FORK_ERR);
            }
            else if(id == 0) // 子进程
            {
                //子进程退出，由孙子进程完成交互
                //这样父进程无需等待任务执行结束，只需继续接受用户的连接
                if(fork() > 0) return;

                //孙子进程关闭监听套接字
                _listensock->Close();

                //回调 -- 与客户端交互
                service(sock, client);
                sock->Close();
                exit(0);
            }
            else
            {
                //父进程关闭与客户端进行IO的文件描述符
                sock->Close();

                //等待子进程
                waitpid(id, nullptr, 0);
            }
        }
        _isrunning = false;
    }
private:
    uint16_t _port; // 端口号
    std::shared_ptr<Socket_t> _listensock = std::make_shared<TcpSocket_t>(); // TCP套接字
    bool _isrunning = false; // 标记是否处于运行状态
};